import { User } from '@app/db/models/user.model';
import {
  Body,
  Controller,
  Request,
  Get,
  Post,
  UseGuards,
} from '@nestjs/common';
import { ReturnModelType } from '@typegoose/typegoose';
import { InjectModel } from 'nestjs-typegoose';
import * as bcrypt from 'bcrypt';
import { JwtService } from '@nestjs/jwt';
import { RsaService } from '@app/rsa';
import { LocalAuthGuard } from 'src/auth/local.guard';
import { PrivateRoute, PublicRoute } from 'src/auth/jwt.guard';
import { Roles } from 'src/auth/role.decorator';

@PublicRoute()
@Controller('user')
export class UserController {
  constructor(
    @InjectModel(User) readonly userModel: ReturnModelType<typeof User>,
    private readonly rsaService: RsaService,
    private readonly jwtService: JwtService,
  ) {}

  @Post('/signup')
  async signup(@Body() createUserDto: User) {
    // 前端传过来的密码是加密的，需要先解密
    const decryptedPassword = this.rsaService.decrypt(createUserDto.password);
    // 保存到数据库的密码需要经过 hash
    const hashedPassword = await bcrypt.hash(decryptedPassword, 10);

    const created = await this.userModel.create({
      ...createUserDto,
      password: hashedPassword,
    });
    return created;
  }

  // 请求这个接口时，会被 guard守卫 拦截
  // 然后调用关联的 strategy策略
  // 最后把返回的数据注入到 req.user 中
  // 注意: 'user' 这个字段名是默认的，目前不知道怎么修改
  @UseGuards(LocalAuthGuard)
  @Post('/login')
  async login(@Request() req: { user: User & { _id: string } }) {
    // LocalAuthGuard 验证返回的 user 不是一个普通对象，需要转化

    // 登录验证通过后，生成 token 并返回给前端
    const access_token = this.jwtService.sign(req.user);

    return {
      user: req.user,
      access_token,
    };
  }

  // 使用这个守卫后就会进行 token 校验
  // 这种写法是单独对这个路由生效的
  // 由于已经使用的全局的 jwt-guard
  // 所以这种写法就不需要了
  // @UseGuards(JwtGuard)

  @PrivateRoute()
  @Get('/get-info')
  async getDetail(@Request() req: { user: User & { _id: string } }) {
    // 通过 token 校验后，就可以根据返回的 req.user 中的信息进行其他的业务
    console.log('get user info', req.user);

    const user = await this.userModel.findById(req.user._id);

    return {
      msg: '用户信息',
      user,
    };
  }

  @Get('/list')
  async findAll() {
    const list = await this.userModel.find().exec();
    return { list };
  }

  // 这个接口需要 token 验证
  // 并且角色是管理员
  @PrivateRoute()
  @Roles('admin')
  @Get('/get-admin-data')
  async getAdminData() {
    return { msg: '只有管理员知晓的世界' };
  }
}
